/**
 * 
 */
package com.bbcare.cp.plat.annotation;

import java.lang.reflect.Method;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

import com.bbcare.comm.AppException;
import com.bbcare.comm.Constants;
import com.bbcare.comm.ErrorCode;
import com.bbcare.comm.IpUtils;
import com.bbcare.comm.PropertiesUtils;

/*
 * @name:         RequestIpLimitAspect.java
 * @author:       tao
 * @createTime:   2018年7月26日
 * @description:  ip限制切面方法
 * @modify:
 * 
 */
@Aspect
@Component
public class RequestIpLimitAspect {
	private final Log logger = LogFactory.getLog(RequestIpLimitAspect.class);
	
	@Resource(name = "jedisPool")
	private JedisPool jedisPool;
	
	@Pointcut("execution(* com.bbcare.*.plat.ctrl.*.*(..)) && @annotation(com.bbcare.cp.plat.annotation.RequestIpLimit)")
    public void before(){
    }
	
	@Before("before()")
    public void requestLimit(JoinPoint joinPoint) throws Exception {
		logger.info("in requestLimit");
		// 获取HttpRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        
        // 判断request不能为空
        if (request == null) {
        	return ;
        }

        RequestIpLimit limit = this.getAnnotation(joinPoint);
        if(limit == null) {  
            return;  
        }  
		String ip = IpUtils.getIpFromRequest(request);
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
            jedis.select(Constants.REDIS_DB_INDEX_EVALUATION); 
            
			String limit_flag = PropertiesUtils.getProperty("limit_flag"); //次数
			if("Y".equalsIgnoreCase(limit_flag) && !StringUtils.isEmpty(ip)){
				//校验一定时间段内 提交次数
				int limitTime = StringUtils.isEmpty(PropertiesUtils.getProperty("iplimit_times"))?10:Integer.parseInt(PropertiesUtils.getProperty("iplimit_times")); //秒
				int limitNum =  StringUtils.isEmpty(PropertiesUtils.getProperty("iplimit_num"))?20:Integer.parseInt(PropertiesUtils.getProperty("iplimit_num")); //分钟//次数
				
				String uri = request.getRequestURI().toString();
				String infPath= "";
				//取最后一个/部分 和 ? 中间部分作为接口名
				int start = uri.lastIndexOf("/");
				int end = uri.indexOf("?");
				if(end != -1){
					infPath = uri.substring(start+1,end);
				}else{
					infPath = uri.substring(start+1);
				}
				String ipLimitKey =Constants.IP_LIMIT_KEY +":" + infPath +":"+ip;

				long limitCount = jedis.incr(ipLimitKey);
				if (limitCount == 1) {
					jedis.setex(ipLimitKey, limitTime,String.valueOf(limitCount));
//	                jedis.expire(ipLimitKey, limitTime);
	            }
				if(limitCount >= limitNum){
					throw new AppException(ErrorCode.EXCEPTION_SYS_IP_LIMIT_TIMES,"系统繁忙请稍后再试");
	            }
			}else{
				return ;
			}
		}catch (JedisConnectionException jex) {
			logger.error("redis连接异常..." + jex.getMessage());
			throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_REDIS_CONNECT_ERROR,"Redis缓存连接失败!"));
		}finally {
			if (null != jedis) {
				try {
					jedis.close();
					logger.warn("close redis connection...");
				} catch (Exception ex) {
					ex.printStackTrace();
					throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_REDIS_CONNECT_CLOSE_FAILED,"Redis缓存关闭失败!"));
				}
			}
		}
	}
	

    /**
     * 
     * @Title: getAnnotation 
     * @Description: 获得注解
     * @param joinPoint
     * @return
     * @throws Exception  参数说明
     */
	private RequestIpLimit getAnnotation(JoinPoint joinPoint) throws Exception {  
        Signature signature = joinPoint.getSignature();  
        MethodSignature methodSignature = (MethodSignature) signature;  
        Method method = methodSignature.getMethod();  

        if (method != null) {  
            return method.getAnnotation(RequestIpLimit.class);  
        }  
        return null;  
    }  
}
